#include "mprpcchannel.h"
#include "rpcheader.pb.h"
#include "mprpcapplication.h"
#include "mprpcchannel.h"

#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>

/**
 * 对 rpc 请求序列化、网络发送
 * 阻塞、同步的方式等待请求结果
 * 数据接收、反序列化，上报业务层
 * header_size（四个字节）  header_str  args_str
 * message RpcHeader  // header_str
 * {
 *      bytes service_name = 1;
 *      bytes method_name = 2;
 *      uint32 args_size = 3;
 * }
*/
void MprpcChannel::CallMethod(const google::protobuf::MethodDescriptor* method,
                              google::protobuf::RpcController* controller,
                              const google::protobuf::Message* request,
                              google::protobuf::Message* response, 
                              google::protobuf::Closure* done)
{
    const google::protobuf::ServiceDescriptor *sd = method->service();  // 方法所属的服务对象

    std::string service_name = sd->name();  // service_name
    std::string method_name = method->name();  // method_name
    uint32_t args_size = 0;  // 参数的序列化后的字符串长度 args_size
    std::string args_str;
    if(request->SerializeToString(&args_str))
    {
        args_size = args_str.size();
    }
    else  // 参数序列化失败
    {
        controller->SetFailed("serialize request error!");
        return ;
    }

    // 定义 rpc 的请求 header RpcHeader
    mprpc::RpcHeader rpcHeader;
    rpcHeader.set_service_name(service_name);
    rpcHeader.set_method_name(method_name);
    rpcHeader.set_args_size(args_size);

    std::string rpc_header_str;  // header 的长度
    uint32_t header_size = 0;
    if(rpcHeader.SerializeToString(&rpc_header_str))  // 序列化 rpcHeader
    {
        header_size = rpc_header_str.size();
    }
    else
    {
        controller->SetFailed("serialize rpc header error!");
        return ;
    }

    // 组织待发送的 rpc 请求的字符串
    // header_size（四个字节）  header_str  args_str
    std::string send_rpc_str;
    send_rpc_str.insert(0, std::string((char*)&header_size, 4));  // header_size（四个字节）
    send_rpc_str += rpc_header_str;  // header_str
    send_rpc_str += args_str;  // args_str

    // 打印调试信息
    std::cout << "========================================" << std::endl;
    std::cout << "header_size: " << header_size << std::endl;
    std::cout << "rpc_header_str: " << rpc_header_str << std::endl;
    std::cout << "service_name: " << service_name << std::endl;
    std::cout << "method_name: " << method_name << std::endl;
    std::cout << "args_str: " << args_str << std::endl;
    std::cout << "========================================" << std::endl;

    // 使用 tcp 编程，完成 rpc 远程调用
    int clientfd = socket(AF_INET, SOCK_STREAM, 0);
    if(clientfd == -1)
    {
        char errtxt[512] = {0};
        sprintf(errtxt, "create socket error! errno: %d", errno);
        controller->SetFailed(errtxt);
        return ;
    }

    std::string ip = MprpcApplication::GetInstance().GetConfig().Load("rpcserverip");
    uint16_t port = atoi(MprpcApplication::GetInstance().GetConfig().Load("rpcserverport").c_str());  // atoi 要的是 char*

    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(sockaddr_in));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(port);
    server_addr.sin_addr.s_addr = inet_addr(ip.c_str());

    // 发起连接，连接 RPC 服务节点
    if(connect(clientfd, (sockaddr *)&server_addr, sizeof(server_addr)) == -1)
    {
        char errtxt[512] = {0};
        sprintf(errtxt, "connect error! errno: %d", errno);
        controller->SetFailed(errtxt);
        close(clientfd);
        return ;
    }

    // 发送数据，发起 rpc 请求
    if(send(clientfd, send_rpc_str.c_str(), send_rpc_str.size(), 0) == -1)
    {
        char errtxt[512] = {0};
        sprintf(errtxt, "send error! errno: %d", errno);
        controller->SetFailed(errtxt);
        close(clientfd);
        return ;
    }

    // 接收 rpc 请求
    char recv_buf[1024] = {0};
    int recv_size = recv(clientfd, recv_buf, 1024, 0);
    if(recv_size == -1)
    {
        char errtxt[512] = {0};
        sprintf(errtxt, "recv error! errno: %d", errno);
        controller->SetFailed(errtxt);
        close(clientfd);
        return ;
    }

    // 反序列化 rpc 调用的响应数据，填到 response
    // std::string response_str(recv_buf, 0, recv_size);  // 出现问题，recv_buf 中遇到 \0 后面的数据就存不下来了，导致后面反序列化失败
    if(response->ParseFromArray(recv_buf, recv_size) == false)
    {
        // char errtxt[512] = {0};
        // snprintf(errtxt, sizeof(errtxt), "parse error! response_str: %s\n", recv_buf);
        std::string errtxt = "parse error! response_str: ";
        errtxt += recv_buf;
        controller->SetFailed(errtxt);
        close(clientfd);
        return ;
    }

    close(clientfd);
}